home *** CD-ROM | disk | FTP | other *** search
/ The PC-SIG Library 9 / The PC-SIG Library on CD ROM - Ninth Edition.iso / 001_100 / DISK0041 / DISK0041.ZIP / MSKERM.ASM < prev    next >
Assembly Source File  |  1984-12-08  |  36KB  |  1,425 lines

  1.     public    prompt, dosnum, curdsk, fpush
  2.     include msdefs.h
  3. ;******************** Version 2.27 ********************************** 
  4. ; KERMIT, Celtic for "free" 
  5. ;
  6. ; The name "Kermit" is a registered trade mark of Henson Associates, Inc.,
  7. ; used by permission.
  8. ;       Kermit-MS Program Version 2.27, December 6,1984
  9. ;       Based on the Columbia University KERMIT Protocol.
  10. ;       Copyright (C) 1982,1983,1984 Trustees of Columbia University
  11. ;
  12. ;       Daphne Tzoar, Jeff Damens
  13. ;       Columbia University Center for Computing Activities
  14. ;       612 West 115th Street
  15. ;       New York, NY  10025
  16. ; Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen, Herm Fischer,
  17. ; Vace Kundakci, and Bernie Eiben for their help and contributions.
  18.  
  19. makseg    equ    26H
  20. deffcb    equ    5cH
  21. setblk    equ    4AH
  22. exec    equ    4BH
  23. env    equ    2CH        ; environment address in psp
  24. terma    equ    10        ; termination address in psp
  25. cline    equ    80H        ; offset in psp of command line
  26. namsiz    equ    20        ; Bytes for file name and size.
  27. maxnam    equ    10
  28. chmod    equ    43H        ; chmod call (used to test for file existence)
  29.  
  30. STACK   SEGMENT PARA STACK 'STACK'
  31.         DW      100 DUP(0)      ; Initialize stack to all zeros.
  32. STK    EQU    THIS WORD
  33. STACK   ENDS
  34.  
  35. datas   segment public 'datas'
  36.     extrn    buff:byte, comand:byte, flags:byte, pack:byte, trans:byte
  37.     extrn    fcb:byte, cpfcb:byte, prmptr:word, inichk:byte
  38.     extrn    machnam:byte
  39.     public    takadr,taklev
  40.  
  41. versio    label    byte
  42.     verdef
  43.     db    cr,lf
  44.     db    'Type ? for help',cr,lf
  45.     db    '$'
  46. tmp    db    ?,'$'
  47. crlf    db      cr,lf,'$'
  48. ermes1  db      cr,lf,'?Unrecognized command$'
  49. ermes3  db      cr,lf,'?Not confirmed$'
  50. erms30    db    cr,lf,'Passed maximum nesting level for TAKE command$'
  51. erms31    db    cr,lf,'Take file not found$'
  52. erms32    db    cr,lf,'File(s) not found$'
  53. erms33    db    cr,lf,'CHKDSK program not found on current disk$'
  54. erms34    db    cr,lf,'This command works only for DOS 2.0 and above$'
  55. erms35    db    cr,lf,'Must specify program name$'
  56. erms36    db    cr,lf,'Could not free memory$'
  57. erms37    db    cr,lf,'Unable to execute program$'
  58. infms1    db    'Really erase *.*? $'
  59. infms8    db    cr,lf,'File(s) erased$'
  60. tmsg5    db    cr,lf,'[closing log file]',cr,lf,'$' ; [jd]
  61. filhlp1 db      ' Command file specification $'
  62. filhlp2 db      ' File specification (possibly wild) $'
  63. filhlp3    db    ' File spec (possibly wild) or confirm with carriage return$'
  64. filmsg    db    ' File specification with optional path name $'
  65. filwmsg    db    ' File specification (possibly wild) with optional path name $'
  66. chkfil    db    0,'CHKDSK  COM'
  67. chkflen    equ    $-chkfil
  68.  
  69. tophlp  db    cr,lf
  70.     db    'BYE',tab,tab
  71.     db    'CLOSE',tab,tab
  72.     db      'CONNECT',tab,tab
  73.     db    'DEFINE',tab,tab
  74.     db    cr,lf
  75.     db    'DELETE',tab,tab
  76.     db    'DIRECTORY',tab
  77.     db    'DO',tab,tab
  78.         db      'EXIT',tab,tab
  79.     db    cr,lf
  80.     db    'FINISH',tab,tab
  81.     db    'GET',tab,tab
  82.         db      'HELP',tab,tab
  83.     db    'LOCAL',tab,tab
  84.     db    cr,lf
  85.     db    'LOG',tab,tab
  86.     db    'LOGOUT',tab,tab
  87.     db    'PUSH',tab,tab
  88.         db      'QUIT',tab,tab
  89.     db    cr,lf
  90.         db      'RECEIVE',tab,tab
  91.     db    'REMOTE',tab,tab
  92.     db    'RUN',tab,tab
  93.         db      'SEND',tab,tab
  94.     db    cr,lf
  95.     db    'SERVER',tab,tab
  96.         db      'SET',tab,tab
  97.     db    'SHOW',tab,tab
  98.     db    'SPACE',tab,tab
  99.     db    cr,lf
  100.         db      'STATUS',tab,tab
  101.     db    'TAKE'
  102.     db    '$'
  103.  
  104. lochlp    db    cr,lf,'DELETE file'
  105.     db    cr,lf,'DIRECTORY [filespec]'
  106.     db    cr,lf,'SPACE remaining on current disk'
  107.     db    cr,lf,'RUN program'
  108.     db    cr,lf,'PUSH to command interpreter'
  109.     db    '$'
  110.  
  111.         ; COMND tables
  112.  
  113. yestab    db    2
  114.     mkeyw    'NO',0
  115.     mkeyw    'YES',1
  116.  
  117. comtab  db    27
  118.     mkeyw    'BYE',bye
  119.     mkeyw    'C',telnet
  120.     mkeyw    'CLOSE',clscpt
  121.     mkeyw    'CONNECT',telnet
  122.     mkeyw    'DEFINE',dodef
  123.     mkeyw    'DELETE',delete
  124.     mkeyw    'DIRECTORY',direct
  125.     mkeyw    'DO',docom
  126.     mkeyw    'EXIT',exit
  127.     mkeyw    'FINISH',finish
  128.     mkeyw    'GET',get
  129.     mkeyw    'HELP',help
  130.     mkeyw    'LOCAL',lclcmd
  131.     mkeyw    'LOG',setcpt
  132.     mkeyw    'LOGOUT',logout
  133.     mkeyw    'PUSH',dopush
  134.     mkeyw    'QUIT',exit
  135.     mkeyw    'RECEIVE',read
  136.     mkeyw    'REMOTE',remote
  137.     mkeyw    'RUN',run
  138.     mkeyw    'SEND',send
  139.     mkeyw    'SERVER',server
  140.     mkeyw    'SET',setcom
  141.     mkeyw    'SHOW',showcmd
  142.     mkeyw    'SPACE',chkdsk
  143.     mkeyw    'STATUS',status
  144.     mkeyw    'TAKE',take
  145.  
  146. loctab    db    5
  147.     mkeyw    'DELETE',delete
  148.     mkeyw    'DIRECTORY',direct
  149.     mkeyw    'PUSH',dopush
  150.     mkeyw    'RUN',run
  151.     mkeyw    'SPACE',chkdsk
  152.  
  153. shotab    db    2
  154.     mkeyw    'KEY',shokey
  155.     mkeyw    'MACROS',shomac
  156.  
  157. ; Program storage.
  158.  
  159. oldstk  dw      ?               ; Storage for system stack.
  160. oldsts  dw      ?               ; System stack segment.
  161. ssave    dw    ?        ; Original SS when doing CHKDSK.
  162. siz    dw    ?        ; Memory size.
  163. in3ad    dd    0        ; Original break interrupt addresses. [25]
  164. curdsk    db    0        ; Current disk. 
  165. origd    db    0        ; Original disk.
  166. fildat    db    0        ; Manipulate file data/time creation.
  167.     db    0
  168. taklev    db    0        ; Take levels. [25t]
  169. takadr    dw    takstr-(size takinfo) ; Pointer into structure. [25t]
  170. temp    dw    0
  171. temp1   dw      ?               ; Temporary storage.
  172. temp2   dw      ?
  173. temp3   dw      ?
  174. temp4   dw      ?
  175. psp    dw    ?
  176. divst    dw    0    
  177. takstr    db    (size takinfo) * maxtak dup(?)
  178. ininam    db    0,'MSKERMITINI'    ; init file name, on default disk, 12 chars
  179. ininm2    db    'MSKERMIT.INI',0 ; init file name for 2.0
  180. nambuf    db    maxnam * namsiz dup (?)
  181. cmdnam    db    namsiz dup (?)
  182. exefcb    db    fcbsiz dup (?)
  183. exefcb2    db    fcbsiz dup (?)
  184. exearg    dw    ?        ; segment addr of environment (filled in below)
  185.     dd    0        ; ptr to cmd line (filled in below)
  186.     dd    exefcb        ; default fcb
  187.     dd    exefcb2        ; second default fcb
  188. dircmd    db    ' /c dir '
  189. dirclen    equ    $-dircmd
  190. dirnam    db    50h dup (?)
  191. chkdcmd    db    'chkdsk.com'
  192. chkdlen    equ    $-chkdcmd
  193. dosnum    db    ?        ; dos version number
  194. pthnam    db    'PATH='
  195. pthlen    equ    $-pthnam
  196. pthbuf    db    100 dup (?)    ; buffer for path definition.
  197. defpth    db    '\', 70 dup (?)    ; buffer for default path
  198. cmspnam    db    'COMSPEC='
  199. cmsplen    equ    $-cmspnam
  200. cmspbuf    db    '\command.com',0 ; default name
  201.     db    30 dup (?)    ; some additional space
  202. tfile    db    100 dup (?)    ; temp space for file names.
  203. eexit    db    cr,'exit',cr
  204. leexit    equ    $-eexit
  205. datas   ends                    ; End data segment
  206.  
  207. code    segment    public 
  208.     public    takrd
  209. start   proc  far
  210.     extrn    cmblnk:near, locate:near, logout:near
  211.     extrn    bye:near, telnet:near, finish:near, comnd:near
  212.     extrn    read:near, remote:near, send:near, status:near, get:near
  213.     extrn    dodisk:near, serrst:near, setcom:near
  214.     extrn    clscpi:near, clscpt:near, getbaud:near
  215.     extrn    dodef:near, setcpt:near, docom:near
  216.     extrn    server:near, lclini:near, shokey:near, shomac:near
  217.     extrn    packlen:near
  218.         assume  cs:code,ds:datas,ss:stack,es:nothing
  219.  
  220.         push ds                 ; Save system data area.
  221.         sub ax,ax               ; Get a zero.
  222.         push ax                 ; Put zero return addr on stack.
  223.  
  224.     mov ax,datas           ; Initialize DS.
  225.         mov ds,ax
  226.     sub ax,ax
  227.  
  228.         mov oldstk,sp           ; Save old stack pointer.
  229.  
  230.     mov ax,es:[2]        ; In program segment prefix
  231.     mov siz,ax        ; Pick up memory size
  232.     mov psp,es    
  233.  
  234.     mov ah,prstr
  235.     mov dx,offset machnam    ; print machine name
  236.     int dos
  237.         mov ah,prstr            ; Print the version header.
  238.         mov dx,offset versio
  239.         int dos
  240.  
  241.     mov ah,setdma        ; Set disk transfer address.
  242.     mov dx,offset buff
  243.     int dos
  244.  
  245.     call getbaud        ; Get the baud rate. [25]
  246.     call dodisk        ; See how many disk drives we have. [21a]
  247.     call setint
  248.     mov ah,gcurdsk        ; Get current disk.
  249.     int dos
  250.     inc al            ; We want 1 == A (not zero).
  251.     mov curdsk,al
  252.     mov origd,al        ; Remember original disk we started on.
  253.     mov ah,dosver
  254.     int dos
  255.     mov dosnum,al        ; remember dos version
  256.     cmp al,0
  257.     je start1        ; 1.1, keep going
  258.     mov es,psp
  259.     mov ax,es:[env]        ; pick up environment address
  260.     push ax
  261.     call getpath        ; get the path from the environment
  262.     pop ax            ; get environment back
  263.     call getcsp        ; get comspec from environment as well
  264. start1:    call lclini        ; do local initialization
  265.     call gcmdlin        ; read command line
  266.     call rdinit        ; read kermit init file
  267.     call packlen        ; Packet length in case do server comand.
  268. ; This is the main KERMIT loop.  It prompts for and gets the users commands.
  269.  
  270. kermit:    mov ax,ds
  271.     mov es,ax        ; make sure this addresses data segment
  272.     mov dx,prmptr        ; get prompt
  273.     call prompt             ; Prompt the user.
  274.     mov pack.state,0    ; Clear the state.
  275.     mov flags.cxzflg,0    ; Reset each itme.
  276.     mov ah,inichk        ; Original or set checksum length.
  277.     mov trans.chklen,ah    ; Reset just in case.
  278.         mov dx,offset comtab
  279.         mov bx,offset tophlp
  280.     mov comand.cmcr,1    ; Allow bare CR's.
  281.         mov ah,cmkey
  282.         call comnd
  283.          jmp kermt2
  284.     mov comand.cmcr,0    ; Not anymore.
  285.         call bx                 ; Call the routine returned.
  286.          jmp kermt3
  287.     cmp flags.extflg,0    ;  Check if the exit flag is set.
  288.     jne krmend        ;  If so jump to KRMEND.
  289.     jmp kermit        ; Do it again.
  290.  
  291. kermt2:    mov dx,offset ermes1    ;  Give an error.
  292.     jmp short kermt4
  293.  
  294. kermt3:    mov dx,offset ermes3    ;  Give an error.
  295. kermt4:    cmp flags.cxzflg,'C'    ; some sort of abort?
  296.     je kermit        ; yes, don't print error message.
  297.     mov ah,prstr
  298.     int dos
  299.     mov flags.droflg,0    ; Reset drive override flag.
  300.     mov flags.nmoflg,0    ; Reset filename override flag.
  301.     mov flags.getflg,0    ; May as well do this one.
  302.     mov flags.cmrflg,0    ; This one too.
  303.     jmp kermit
  304.  
  305. krmend: call serrst        ; Just in case the port wasn't reset. [21c] 
  306.     mov dl,origd        ; Original disk drive.
  307.     dec dl            ; Want A == 0.
  308.     mov ah,seldsk        ; Reset original disk just in case.
  309.     int dos
  310.     mov sp,oldstk
  311.     ret
  312.  
  313. START    ENDP
  314.  
  315. ; This is the 'exit' command.  It leaves KERMIT and returns to DOS.
  316.  
  317. EXIT    PROC    NEAR
  318.     mov ah,cmcfm
  319.     call comnd        ; Get a confirm.
  320.      jmp r
  321.     test    flags.capflg,0FFH    ; capturing?
  322.     jz    exit1            ; no, keep going
  323.     mov    dx,offset tmsg5
  324.     mov    ah,prstr
  325.     int    dos
  326.     call    clscpi
  327.      nop                ; this skip returns...
  328.      nop
  329.      nop
  330. exit1:
  331.     mov flags.extflg,1    ;  Set the exit flag.
  332.     jmp rskp        ; Then return to system.
  333. EXIT    ENDP
  334.  
  335.  
  336. ; This is the 'help' command.  It gives a list of the commands.
  337.  
  338. HELP    PROC    NEAR
  339.     mov ah,cmcfm
  340.     call comnd        ; Get a confirm.
  341.      jmp r
  342.     mov ah,prstr        ; Print a string to the console.
  343.     mov dx,offset tophlp    ; The address of the help message.
  344.     int dos
  345.     jmp rskp
  346. HELP    ENDP
  347.  
  348. lclcmd    proc    near
  349.     mov ah,cmkey
  350.     mov dx,offset loctab
  351.     mov bx,offset lochlp
  352.     call comnd
  353.      jmp r
  354.     call bx
  355.     nop
  356.     nop
  357.     nop
  358.     jmp rskp
  359. lclcmd    endp
  360.  
  361. ; Don't ignore ^C when in debug mode.
  362. SETINT    PROC    NEAR
  363.     push ds            ; Don't forget this. [25]
  364.     mov ax,ds
  365.     mov es,ax        ; So can access our data area.
  366.     mov ax,0
  367.     mov ds,ax        ; Access low core.
  368.     mov ax,ds:[23H * 4]    ; Address for interrupt 23H.
  369.     mov cx,ds:[23H * 4 +2]    ; CS value for it.
  370.     mov word ptr es:in3ad,ax ; Remember original values.
  371.     mov word ptr es:in3ad+2,cx
  372.     mov ax,cs
  373.     mov ds,ax        ; Access code are.
  374.     mov dx,offset intbrk
  375.     mov al,23H        ; On ^C, goto above address.
  376.     mov ah,25H
  377.     int dos
  378.     pop ds
  379.     ret
  380. SETINT    ENDP
  381.  
  382. ; take commands from a file, but allow a path name
  383. PTAKE    PROC    NEAR
  384.     cmp taklev,maxtak        ; Hit our limit?
  385.     jl ptake1            ; Continue if still OK.
  386.     mov ah,prstr
  387.     mov dx,offset erms30        ; Complain.
  388.     int dos 
  389.     ret
  390. ptake1:    mov di,takadr
  391.     add di,size takinfo
  392.     push di
  393.     mov ah,cmtxt
  394.     lea bx,[di].takbuf        ; convenient place to parse name into
  395.     mov dx,offset filmsg        ; Help in case user types "?".
  396.     call comnd
  397.      pop di
  398.      ret
  399.      nop
  400.     pop di                ; restore frame address
  401.     cmp ah,0
  402.     je ptake2            ; empty, complain.
  403.     push di                ; keep it on stack.
  404.     lea si,[di].takbuf        ; get buffer back
  405.     mov bl,ah            ; length of thing parsed
  406.     mov bh,0
  407.     mov byte ptr [bx+si],0        ; make it asciz
  408.     mov ax,si            ; point to name again
  409.     call spath            ; is it around?
  410.     pop di                ; need this back
  411.     jc ptake2            ; no, go complain
  412.     mov dx,ax            ; point to name from spath
  413.     mov ah,open2            ; 2.0 open call
  414.     mov al,0            ; open for reading
  415.     int dos
  416.     jnc ptake3            ; open ok, keep going
  417. ptake2:    mov ah,prstr
  418.     mov dx,offset erms31
  419.     int dos
  420.     ret
  421. ptake3:    inc taklev
  422.     mov takadr,di
  423.     mov word ptr [di].takfcb+1,ax    ; save file descriptor
  424.     mov byte ptr [di].takfcb,0feh    ; mark as 2.0 file descriptor
  425.     mov bx,ax            ; need descriptor here
  426.     mov ah,lseek
  427.     mov al,2
  428.     mov cx,0
  429.     mov dx,cx            ; seek 0 bytes from end
  430.     int dos
  431.     mov [di].takcnt,ax
  432.     mov [di].takcnt+2,dx        ; store length
  433.     mov ah,lseek
  434.     mov al,0
  435.     mov cx,0
  436.     mov dx,cx            ; now seek back to beginning
  437.     int dos
  438.     cmp flags.takflg,0
  439.     je ptake4
  440.     mov ah,prstr
  441.     mov dx,offset crlf
  442.     int dos
  443. ptake4:    call takrd        ; Get a buffer full of data.
  444.     jmp rskp
  445. PTAKE    ENDP
  446.  
  447.  
  448. ;     TAKE commands from a file.  [25t]
  449.  
  450. TAKE    PROC    NEAR
  451.     cmp dosnum,0
  452.     je take1
  453.     jmp ptake            ; use this for 2.0
  454. take1:    cmp taklev,maxtak        ; Hit our limit?
  455.     jl take2                ; Continue if still OK.
  456.     mov ah,prstr
  457.     mov dx,offset erms30        ; Complain.
  458.     int dos 
  459.     ret
  460. take2:    mov bx,takadr
  461.     add bx,size takinfo
  462.     push bx
  463.     lea dx,[bx].takfcb
  464.      mov comand.cmcr,0        ; Filename must be specified.
  465.     mov ah,cmifi
  466.     mov bx,offset filhlp1
  467.     call comnd
  468.      pop bx
  469.      ret                ; Make sure this is three bytes long.
  470.      nop
  471.     pop bx
  472.     mov byte ptr [bx].takfcb+32,0    ; have to clear current record in fcb
  473.     mov ah,openf
  474.     lea dx,[bx].takfcb
  475.     int dos
  476.     cmp al,0FFH            ; File not found?
  477.     jne take3
  478.     mov ah,prstr
  479.     mov dx,offset erms31
  480.     int dos
  481. take3:    inc taklev
  482.     mov takadr,bx
  483.     mov ax,word ptr [bx+16].takfcb
  484.     mov [bx].takcnt,ax
  485.     mov ax,word ptr [bx+18].takfcb
  486.     mov [bx].takcnt+2,ax        ; copy size into takinfo
  487.     cmp flags.takflg,0
  488.     je take4
  489.     mov ah,prstr
  490.     mov dx,offset crlf
  491.     int dos
  492. take4:    call takrd            ; Get a buffer full of data.
  493.     jmp rskp
  494. TAKE     ENDP
  495.  
  496. TAKRD    PROC    NEAR
  497.     push bx
  498.     push cx    
  499.     push dx
  500.     mov bx,takadr
  501.     cmp byte ptr [bx].takfcb,0feh    ; is it a 2.0 file handle?
  502.     jne takrd1            ; no, handle differently
  503.     push bx                ; save frame address
  504.     lea dx,[bx].takbuf        ; buffer to read into
  505.     mov cx,dmasiz            ; # of bytes to read
  506.     mov ah,readf2            ; 2.0 read call
  507.     mov bx,word ptr [bx].takfcb+1    ; file handle is stored here
  508.     int dos
  509.     pop bx                ; restore frame address
  510.     jmp takrd2            ; rejoin common exit
  511.  
  512. takrd1:    mov ah,setdma
  513.     lea dx,[bx].takbuf
  514.     int dos
  515.     mov ah,readf
  516.     lea dx,[bx].takfcb
  517.     int dos
  518.     mov ah,setdma
  519.     lea dx,buff
  520.     int dos
  521. takrd2:    mov [bx].takchl,dmasiz
  522.     lea ax,[bx].takbuf
  523.     mov [bx].takptr,ax
  524.     pop dx
  525.     pop cx
  526.     pop bx
  527.     ret
  528.  
  529. TAKRD    ENDP
  530.  
  531. ; copy the path into pthbuf
  532. ; enter with ax/ environment segment address
  533. ; works in 2.0 only.
  534. getpath    proc    near
  535.     push    es
  536.     mov    bx,ds
  537.     mov    es,bx            ; address data segment
  538.     mov    bx,offset pthnam    ; thing to find
  539.     mov    cx,pthlen        ; length of it
  540.     mov    dx,offset pthbuf    ; place to put it
  541.     mov    byte ptr pthbuf,0    ; initialize to null...
  542.     call    getenv            ; get environment value
  543.     pop    es
  544.     ret                ; and return
  545. getpath    endp
  546.  
  547. ; copy the comspec into cmspbuf
  548. ; enter with ax/ environment segment address
  549. ; works in 2.0 only.
  550. getcsp    proc    near
  551.     push    es
  552.     mov    bx,ds
  553.     mov    es,bx            ; address data segment
  554.     mov    bx,offset cmspnam    ; thing to find
  555.     mov    cx,cmsplen        ; length of it
  556.     mov    dx,offset cmspbuf    ; place to put it
  557.     call    getenv            ; get environment value
  558.     pop    es
  559.     ret                ; and return
  560. getcsp    endp
  561.  
  562. ; find a path variable.  Enter with ax/ environment segment,
  563. ; bx/ variable to find (incl =), cx/ length of variable name,
  564. ; dx/ address to store value at.
  565. ; The buffer given in dx is unchanged if the variable isn't found
  566. getenv    proc    near
  567.     push    ds
  568.     push    es
  569.     mov    es,ax            ; address segment
  570.     mov    di,0            ; offset in segment
  571. geten1:    cmp    es:byte ptr [di],0    ; end?
  572.     je    geten4            ; yes, forget it
  573.     push    cx            ; save counter
  574.     push    di            ; and offset
  575.     mov    si,bx
  576.     repe    cmpsb            ; is it the one?
  577.     pop    di
  578.     pop    cx            ; restore these
  579.     je    geten2            ; found it, break loop
  580.     push    cx            ; preserve again
  581.     mov    cx,0ffffh        ; bogus length
  582.     mov    al,0            ; marker to look for
  583.     repne    scasb            ; search for it
  584.     pop    cx            ; restore length
  585.     jmp    geten1            ; loop thru rest of environment
  586. geten2:    add    di,cx            ; skip to definition
  587.     mov    si,di            ; this is source
  588.     mov    di,dx            ; destination as given
  589.     mov    ax,ds
  590.     mov    bx,es
  591.     mov    ds,bx
  592.     mov    es,ax            ; exchange segment regs for copy
  593. geten3:    lodsb                ; get a byte
  594.     stosb                ; drop it off
  595.     cmp    al,0            ; end of string
  596.     jne    geten3            ; no, go on
  597. geten4:    pop    es
  598.     pop    ds            ; restore registers
  599.     ret                ; and return
  600. getenv    endp
  601.  
  602. ; put kermit.ini onto take stack if it exists.  Just like
  603. ; the take command, except it doesn't read a filename.
  604.  
  605. rdinit    proc    near        ; read kermit init file...
  606.     mov al,dosnum        ; get dos version
  607.     or al,al
  608.     jne rdini4        ; post 2.0, use file handle instead...
  609.     mov bx,takadr
  610.     add bx,size takinfo    ; bump take ptr, point to current take frame
  611.     lea di,[bx].takfcb    ; destination is fcb
  612.     mov ax,ds
  613.     mov es,ax        ; destination segment = source segment
  614.     mov si,offset ininam    ; name of init file
  615.     mov cx,12        ; 8 char name + 3 char ext + 1 char drive...
  616.     rep movsb        ; copy it in
  617.     mov byte ptr [bx].takfcb+32,0 ; have to clear current record in fcb
  618.     mov ah,openf
  619.     lea dx,[bx].takfcb
  620.     int dos
  621.     cmp al,0FFH        ; File not found?
  622.     jne rdini1        ; no, keep going
  623.     ret            ; else just return, no init file
  624. rdini1:    inc taklev        ; bump take level
  625.     mov takadr,bx        ; save current take frame ptr
  626.     mov ax,word ptr [bx+16].takfcb
  627.     mov [bx].takcnt,ax
  628.     mov ax,word ptr [bx+18].takfcb
  629.     mov [bx].takcnt+2,ax    ; copy size into takinfo
  630. rdini2:    cmp flags.takflg,0
  631.     je rdini3
  632.     mov ah,prstr
  633.     mov dx,offset crlf
  634.     int dos
  635. rdini3:    call takrd        ; Get a buffer full of data.
  636.     ret
  637.  
  638. rdini4:    mov ax,offset ininm2    ; name to try
  639.     push bx
  640.     call spath        ; can we find it?
  641.     pop di
  642.     jc rdini6        ; no, forget it, go use it
  643.     mov dx,ax        ; point to name
  644.     mov ah,open2        ; 2.0 open function
  645.     mov al,0        ; for reading...
  646.     int dos
  647.     jc rdini6        ; can't open, forget it
  648.  
  649. rdini5:    inc taklev        ; bump take level
  650.     add takadr,size takinfo
  651.     mov di,takadr        ; get current frame ptr
  652.     mov word ptr [di].takfcb+1,ax    ; save file handle
  653.     mov byte ptr [di].takfcb,0feh    ; mark as a handle
  654.     mov bx,ax            ; move file ptr
  655.     mov ah,lseek
  656.     mov al,2
  657.     mov cx,0
  658.     mov dx,0            ; seek to end of file
  659.     int dos
  660.     mov [di].takcnt,ax        ; copy file size
  661.     mov [di].takcnt+2,dx        ; into structure
  662.     mov al,0
  663.     mov ah,lseek
  664.     mov cx,0
  665.     mov dx,0
  666.     int dos                ; seek back to beginning
  667.     jmp rdini2            ; go rejoin common exit
  668. rdini6:    ret                ; no init file, just return
  669. rdinit    endp
  670.  
  671. ; get command line into a macro buffer.
  672.  
  673. gcmdlin    proc    near
  674.     push    ds
  675.     push    es
  676.     cld
  677.     mov    es,psp            ; address psp
  678.     mov    ch,0
  679.     mov    cl,es:[cline]        ; length of cmd line
  680.     mov    di,cline+1        ; point to actual line
  681.     mov    al,' '
  682.     jcxz    gcmdl3            ; no command line, forget it.
  683.     repe    scasb            ; skip over spaces
  684.     je    gcmdl3            ; all spaces, forget it
  685.     mov    si,di            ; this is first non-space
  686.     dec    si            ; pre-incremented...
  687.     inc    cx
  688.     inc    taklev            ; bump take level
  689.     add    takadr,size takinfo    ; address new take frame
  690.     mov    bx,takadr
  691.     mov    byte ptr [bx].takfcb,0ffh ; mark as a macro
  692.     push    cx            ; save length
  693.     push    ds            ; and segment
  694.     lea    di,[bx].takbuf        ; into take buffer
  695.     mov    ax,ds
  696.     mov    ds,psp
  697.     mov    es,ax            ; switch segments for copy
  698. gcmdl1:    lodsb                ; get a byte
  699.     cmp    al,','            ; comma?
  700.     jne    gcmdl2            ; no, keep going
  701.     mov    al,cr            ; convert to cr
  702. gcmdl2:    stosb                ; deposit it
  703.     loop    gcmdl1            ; copy whole cmd
  704.     pop    ds            ; restore segment
  705.     mov    si,offset eexit        ; something to tack onto end
  706.     mov    cx,leexit        ; length of it
  707.     rep    movsb            ; copy it in
  708.     pop    cx            ; restore len
  709.     add    cx,leexit        ; count wnat we added
  710.     
  711.     lea    ax,[bx].takbuf
  712.     mov    [bx].takptr,ax        ; init buffer ptr
  713.     mov    [bx].takchl,cl        ; chars remaining
  714.     mov    [bx].takcnt,cx        ; and all chars
  715.     mov    [bx].takcnt+2,0        ; clear high order
  716. gcmdl3:    pop    es
  717.     pop    ds
  718.     ret
  719. gcmdlin    endp
  720.  
  721. ;    This routine prints the prompt and specifies the reparse address.
  722.  
  723. PROMPT    PROC  NEAR
  724.     mov comand.cmprmp,dx    ; save the prompt
  725.     pop bx            ; Get the return address.
  726.     mov comand.cmrprs,bx    ; Save as addr to go to on reparse.
  727.     mov comand.cmostp,sp    ; Save for later restoral.
  728.     push bx            ; Put it on the stack again.
  729.     mov bx,offset comand.cmdbuf
  730.     mov comand.cmcptr,bx    ; Initialize the command pointer.
  731.     mov comand.cmdptr,bx
  732.     mov ah,0
  733.     mov comand.cmaflg,ah    ; Zero the flags.
  734.     mov comand.cmccnt,ah
  735.     mov comand.cmsflg,0FFH
  736.     cmp flags.takflg,0    ; look at take flag
  737.     jne promp1        ; supposed to echo, skip this check...
  738.     cmp taklev,0        ; inside a take file?
  739.     je promp1        ; no, keep going
  740.     ret            ; yes, return
  741. promp1:    mov ah,prstr
  742.     mov dx,offset crlf
  743.     int dos
  744.     mov ah,prstr        ; Print the prompt.
  745.     mov dx,comand.cmprmp
  746.     int dos
  747.     ret
  748. PROMPT    ENDP
  749.  
  750. ; Erase specified file(s).
  751. DELETE    PROC    NEAR
  752.      mov comand.cmcr,0    ; Filename must be specified.
  753.     mov ah,cmifi        ; Parse an input filespec.
  754.     mov dx,offset fcb
  755.     mov bx,offset filhlp2    ; Text of help message.
  756.     call comnd
  757.      jmp r            ; Bad filename.
  758.     mov ah,cmcfm        ; Parse a confirm.
  759.     call comnd
  760.      jmp r
  761.     cld
  762.     mov di,offset fcb+1
  763.     mov al,'?'
  764.     mov cx,11        ; # of chars in a name
  765.     repe scasb        ; are they all ?'s?
  766.     jne del1        ; no, skip message
  767.     mov dx,offset infms1
  768.     call prompt
  769.     mov ah,cmkey
  770.     mov dx,offset yestab
  771.     mov bx,0
  772.     call comnd
  773.      jmp r
  774.     push bx
  775.     mov ah,cmcfm
  776.     call comnd
  777.      pop bx
  778.      ret
  779.      nop
  780.     pop bx
  781.     cmp bx,0
  782.     jne del1
  783.     jmp rskp
  784. del1:    mov dx,offset fcb
  785.     mov ah,sfirst        ; See if any files match this specification.
  786.     int dos    
  787.     cmp al,0FFH        ; No matches?
  788.     jne del2
  789.     mov ah,prstr
  790.     mov dx,offset erms32
  791.     int dos
  792.     jmp rskp
  793. del2:    mov dx,offset fcb
  794.     mov ah,delf        ; Erase the file(s).
  795.     int dos
  796.     mov dx,offset infms8
  797.     mov ah,prstr        ; Say we did so.
  798.     int dos
  799.     jmp rskp
  800. DELETE    ENDP    
  801.  
  802. CHKDSK    PROC    NEAR
  803.     mov ah,cmcfm
  804.     call comnd
  805.      jmp r
  806.     cmp dosnum,0
  807.     je chkds1            ; yes, have to do it the hard way
  808.     mov si,offset chkdcmd        ; point to cmd
  809.     mov cx,chkdlen            ; and length
  810.     jmp crun            ; and go execute it nicely
  811. chkds1:    push es
  812.     mov ax,ds
  813.     mov es,ax
  814.     mov di,offset fcb
  815.     mov si,offset chkfil
  816.     mov cx,chkflen
  817.     rep movsb
  818.     mov dx,offset stk + 15        ; End of stack plus roundoff.
  819.     mov cl,4
  820.     shr dx,cl            ; Divide to get segment.
  821.     add dx,seg stack        ; Get past the stack.
  822.     mov es,dx            ; remember where segment is.
  823.     mov ah,makseg            ; Create new PSP.
  824.     int dos
  825.     mov ax,siz            ; Update machine size.
  826.     mov es:2,ax
  827.     mov es: byte ptr [deffcb],0    ; Blank default fcb.
  828.     mov di,deffcb+1
  829.     mov al,' '            ; Blank out fcb.
  830.     mov cx,fcbsiz
  831.     rep stosb
  832.     mov word ptr es:[terma],offset term    ; Termination address.
  833.     mov es:[terma+2],cs
  834.     mov ah,openf
  835.     mov dx,offset fcb
  836.     int dos
  837.     inc al
  838.     jnz chkok
  839.     mov dx,offset erms33
  840.     mov ah,prstr
  841.     int dos
  842.     jmp chkend
  843.  
  844. chkok:    mov byte ptr fcb+32,0        ; set current record field
  845.     mov di,100h            ; offset to copy into
  846. lp:    mov dx,offset fcb
  847.     mov ah,readf
  848.     int dos
  849.     push ax                ; save status
  850.     mov si,offset buff
  851.     mov cx,dmasiz/2            ; Word size of DMA
  852.     rep movsw            ; copy into new segment...
  853.     pop ax
  854.     cmp al,1            ; End of file
  855.     je dun
  856.     cmp al,3            ; Done here too
  857.     jne lp
  858. dun:    mov ssave,sp            ; Save stack pointer.
  859.     mov ax,es
  860.     mov word ptr cs:[doit+2],ax     ; Set segment for CHKDSK.
  861.     mov ds,ax
  862.     mov ss,ax
  863.     mov ax,0
  864.     jmp cs: dword ptr [doit]    ; Call CHKDSK.
  865. term:    mov ax,seg datas        ; Reset data area.
  866.     mov ds,ax
  867.     mov sp,ssave
  868.     mov ax,seg stack
  869.     mov ss,ax
  870.     mov ah,setdma
  871.     mov dx,offset buff
  872.     int dos                ; restore dma address!!
  873. chkend:    pop es
  874.     jmp rskp
  875. doit    dd 100h
  876. CHKDSK    ENDP
  877.  
  878. ; Get directory listing.
  879. DIRECT    PROC    NEAR
  880.     mov ah,dosver        ; See what level of DOS we're at.
  881.     int dos
  882.     cmp al,0        ; Level 2.0 or above?
  883.     jne dir4        ; Yes - get directory the easy way.
  884.     mov comand.cmcr,1    ; Allow plain CR (so DIR == DIR *.*).
  885.     mov ah,cmifi        ; Get input file spec.
  886.     mov dx,offset fcb    ; Give the address for the FCB.
  887.     mov bx,offset filhlp3
  888.     call comnd
  889.      jmp r
  890.     mov ah,cmcfm        ; Parse a confirm.
  891.     call comnd
  892.      jmp r
  893.     mov comand.cmcr,0    ; Reset this. 
  894.     push es
  895.     mov ax,ds
  896.     mov es,ax
  897.     mov temp1,0FFH
  898.     mov di,offset nambuf
  899. dir0:    call getfn        ; Get a matching file name.
  900.     cmp al,0FFH        ; Retcode -- are we done?
  901.     je dir1            ; Yes, just leave.
  902.     call dumpit        ; Print it or dump to buffer.
  903.     jmp dir0
  904. dir1:    pop es
  905.     jmp rskp
  906.  
  907. dir4:    mov si,offset cmspbuf    ; command processor
  908.     mov di,offset dirnam
  909. dir5:    lodsb            ; get a byte
  910.     or al,al
  911.     jz dir6            ; stop on the null
  912.     stosb            ; otherwise copy it in
  913.     jmp dir5        ; and keep going
  914. dir6:    mov si,offset dircmd    ; add directory command to it
  915.     mov cx,dirclen
  916.     rep movsb
  917.     mov ah,cmtxt        ; parse with cmtxt so we can have paths...
  918.     mov bx,di        ; next available byte
  919.     mov dx,offset filwmsg    ; In case user wants help. 
  920.     call comnd
  921.      jmp r
  922.     mov cl,ah
  923.     mov ch,0        ; length of name
  924.     sub di,offset dirnam    ; compute # of bytes used
  925.     add cx,di
  926.     mov si,offset dirnam    ; dir cmd
  927.     jmp crun        ; join run cmd from there.
  928. DIRECT    ENDP
  929.  
  930. getfn:    cmp temp1,0FFH
  931.     jne gtfn1
  932.     mov ah,sfirst        ; Any matches?
  933.     mov dx,offset fcb
  934.     int dos
  935.     cmp al,0FFH        ; Means no matches.
  936.     je gtfn5
  937.     call savfcb
  938.     mov temp1,0
  939.     jmp gtfn4
  940. gtfn1:    cmp flags.wldflg,0FFH    ; Wilcard seen?
  941.     je gtfn2        ; Yes, get next file.
  942.     mov al,0FFH        ; No, set retcode.
  943.     ret
  944. gtfn2:    call rstfcb
  945.     mov ah,snext
  946.     mov dx,offset fcb
  947.     int dos
  948.     cmp al,0        ; Any more matches?
  949.     je gtfn3        ; Yes keep going.
  950.     mov al,0FFH        ; OK return code.
  951.     ret
  952. gtfn3:    call savfcb
  953. gtfn4:    push di
  954.     mov si,offset buff    ; Data is here.
  955.     mov di,offset fcb    ; Copy to here.
  956.     mov cx,37
  957.     repne movsb
  958.     pop di
  959.     call nicnam        ; Make name nice for printing.
  960.     mov al,0
  961.     ret
  962. gtfn5:    mov ah,prstr        ; Don't print if a server. 
  963.     mov dx,offset erms32    ; Say no matches.
  964.     int dos
  965.     mov al,0FFH        ; Failure return code.
  966.     ret
  967.  
  968. savfcb:    push di
  969.     mov si,offset fcb    ; Data is here.
  970.     mov di,offset cpfcb    ; Copy to here.
  971.     mov cx,37
  972.     repne movsb
  973.     pop di
  974.     ret
  975.  
  976. rstfcb:    push di
  977.     mov si,offset cpfcb    ; Data is here.
  978.     mov di,offset fcb    ; Copy to here.
  979.     mov cx,37
  980.     repne movsb
  981.     pop di    
  982.     ret
  983.  
  984. nicnam:    mov al,CR        ; Add CRLF before print names
  985.     stosb
  986.     mov al,LF
  987.     stosb
  988.     mov cx,8
  989.     mov si,offset fcb+1
  990.     repne movsb        ; Get the file name.
  991.     mov al,' '
  992.     stosb
  993.     mov cx,3
  994.     repne movsb
  995.     mov al,tab
  996.     stosb
  997.     mov al,' '
  998.     stosb
  999.     mov ah,openf
  1000.     mov dx,offset fcb
  1001.     int dos    
  1002.     mov bx,offset fcb+18    ; Get hi order word of file size.
  1003.     mov ax,[bx]
  1004.     mov dx,ax
  1005.     mov bx,offset fcb+16    ; Get lo order word.
  1006.     mov ax,[bx]
  1007.     call nout2x        ; Get it in decimal. 
  1008.     mov al,tab
  1009.     stosb
  1010.     mov al,' '
  1011.     stosb
  1012.     mov ah,0
  1013.     mov si,offset fcb+20
  1014.     lodsb
  1015.     mov fildat+1,al
  1016.     lodsb
  1017.     mov fildat,al        ; Date field of fcb.
  1018.     mov cl,5
  1019.     shr fildat+1,cl
  1020.     and fildat,1
  1021.     mov cl,3
  1022.     shl fildat,cl
  1023.     mov al,fildat
  1024.     or al,fildat+1        ; Get the month field.
  1025.     cmp al,9
  1026.     jg nic0
  1027.     push ax
  1028.     mov al,' '
  1029.     stosb
  1030.     pop ax
  1031. nic0:    call nout2        ; Make it decimal.
  1032.     mov al,'-'
  1033.     stosb
  1034.     mov si,offset fcb+20    ; Get date field.
  1035.     lodsb
  1036.     and al,1FH
  1037.     cmp al,10        ; Only one digit?
  1038.     jge nic0x
  1039.     push ax
  1040.     mov al,'0'        ; Make it two digits.
  1041.     stosb
  1042.     pop ax
  1043. nic0x:    call nout2        ; Make it decimal.
  1044.     mov al,'-'
  1045.     stosb
  1046.     mov si,offset fcb+21    ; Get the year field.
  1047.     lodsb
  1048.     shr al,1
  1049.     add al,80
  1050.     cmp al,100        ; At the year 2000 or above?
  1051.     js nic0y        ; No, just go on.
  1052.     sub al,100        ; Go back to two digits.
  1053. nic0y:    cmp al,10        ; Only one digit?
  1054.     jge nic0z
  1055.     push ax
  1056.     mov al,'0'        ; Make it two digits.
  1057.     stosb
  1058.     pop ax
  1059. nic0z:    call nout2        ; Make it decimal.
  1060.     mov al,tab
  1061.     stosb
  1062.     mov si,offset fcb+23    ; Get time field of fcb.
  1063.     lodsb
  1064.     mov cl,3        ; Get the hour field.
  1065.     shr al,cl
  1066.     mov tmp,'a'        ; For AM.
  1067.     cmp al,12        ; Before noon?
  1068.     jl nic1
  1069.     mov tmp,'p'        ; It's PM.
  1070.     je nic1            ; Don't change "12" to "0".
  1071.     sub al,12        ; Use a 12 hr. clock.
  1072. nic1:    cmp al,0        ; Just after midnight?
  1073.     jne nic1x
  1074.     add al,12        ; Make it "12" instead of "0".
  1075. nic1x:    cmp al,10        ; Pad with a space?
  1076.     jge nic2
  1077.     push ax
  1078.     mov al,' '
  1079.     stosb
  1080.     pop ax
  1081. nic2:    call nout2        ; Make it decimal.
  1082.     mov al,':'        ; Separate hours and minutes.
  1083.     stosb
  1084.     mov si,offset fcb+23    ; Get the minutes field.
  1085.     lodsb
  1086.     and al,07
  1087.     mov cl,3
  1088.     shl al,cl
  1089.     mov ah,al
  1090.     mov si,offset fcb+22
  1091.     lodsb
  1092.     mov cl,5
  1093.     shr al,cl
  1094.     or al,ah
  1095.     mov ah,0
  1096.     cmp al,10        ; Would there be a leading zero.
  1097.     jge nic3
  1098.     push ax
  1099.     mov al,'0'
  1100.     stosb
  1101.     pop ax
  1102. nic3:    call nout2        ; Make it decimal.
  1103.     mov al,tmp        ; Add 'a' (AM) or 'p' (PM).
  1104.     stosb
  1105.     mov ah,closf
  1106.     mov dx,offset fcb
  1107.     int dos
  1108.     ret
  1109.  
  1110. ; For now, just print it.
  1111. dumpit:    mov al,'$'
  1112.     stosb
  1113.     mov ah,prstr
  1114.     mov dx,offset nambuf
  1115.     int dos
  1116.     mov di,offset nambuf
  1117.     ret
  1118.  
  1119. ; push to an inferior command parser
  1120. ; entry fpush (fast push...) pushes without waiting for a confirm.
  1121. ; returns rskp.
  1122. dopush    proc    near
  1123.     cmp    dosnum,0        ; < 2.0 ?
  1124.     jne    dopus1            ; no, go on
  1125.     mov    dx,offset erms34
  1126.     mov    ah,prstr
  1127.     int    dos
  1128.     jmp    rskp
  1129. dopus1:    mov    ah,cmcfm
  1130.     call    comnd
  1131.      jmp    r
  1132. fpush:    mov    si,offset cmspbuf    ; name of parser
  1133.     push    si            ; save beginning
  1134.     sub    cx,cx            ; initial length
  1135. dopus2:    lodsb
  1136.     inc    cx            ; count this
  1137.     or    al,al            ; at end?
  1138.     jnz    dopus2            ; no, keep going
  1139.     pop    si            ; restore cmd
  1140.     dec    cx            ; this is incremented one over
  1141.     jmp    short crun        ; go run it
  1142. dopush    endp
  1143.  
  1144. ; crun - run an arbitrary program.  Enter with si/address of whole
  1145. ; cmd, cx/length of cmd.
  1146. CRUN    proc    near
  1147.     push cx            ; save length of cmd
  1148.     mov ax,ds
  1149.     mov es,ax        ; address dest segment
  1150.     mov di,offset nambuf
  1151.     rep movsb        ; copy command so we can mess with it
  1152.     pop cx
  1153.     mov si,offset nambuf    ; point to command
  1154.     jmp short run3        ; and join run code
  1155. CRUN    ENDP
  1156.  
  1157. RUN    PROC    NEAR
  1158.     cmp dosnum,0
  1159.     jne run1
  1160.     mov ah,prstr
  1161.     mov dx,offset erms34    ; Complain.
  1162.     int dos
  1163.     jmp rskp
  1164. run1:    mov ah,cmtxt        ; Get program name.
  1165.     mov bx,offset nambuf    ; Convenient buffer.
  1166.     mov dx,offset filmsg    ; In case user wants help.
  1167.     call comnd
  1168.      nop
  1169.      nop
  1170.      nop
  1171.     cmp ah,0
  1172.     jne run2
  1173.     mov ah,prstr
  1174.     mov dx,offset erms35
  1175.     int dos
  1176.     jmp rskp
  1177. run2:    mov cl,ah
  1178.     mov ch,0
  1179.     mov si,offset nambuf
  1180.  
  1181. ; alternate entry if cmd is already known.  Source cmd ptr in si
  1182. ; is trashed.
  1183. run3:    mov bx,cx
  1184.     mov byte ptr [si+bx],cr    ; end string with a cr for dos.
  1185.     mov di,offset cmdnam
  1186.     mov ax,ds
  1187.     mov es,ax
  1188. run4:    lodsb
  1189.     cmp al,' '
  1190.     jne run5
  1191.     dec si            ; back up over space
  1192.     jmp short run6        ; and exit loop
  1193. run5:    stosb
  1194.     loop run4
  1195. run6:    mov byte ptr [di],0    ; terminate string
  1196.     dec si            ; point back a byte into argument
  1197.     mov [si],cl        ; put length of argument here
  1198.     mov exearg+2,si        ; pointer to argument string
  1199.     mov exearg+4,ds        ; segment of same
  1200.     inc si            ; pass length over
  1201.     mov al,1        ; scan leading separators
  1202.     mov di,offset exefcb    ; parse into this fcb
  1203.     mov ah,prsfcb
  1204.     int dos            ; go parse the fcb
  1205.     mov al,1        ; scan leading separators
  1206.     mov di,offset exefcb2    ; second fcb to fill
  1207.     mov ah,prsfcb
  1208.     int dos            ; parse the fcb
  1209.     mov es,psp        ; point to psp again
  1210.     mov ax,es:[env]        ; get environment ptr
  1211.     mov exearg,ax        ; put into argument block
  1212.     mov bx,offset stk + 15    ; end of pgm
  1213.     mov cl,4
  1214.     shr bx,cl        ; compute # of paragraphs in last segment
  1215.     mov ax,seg stack    ; end of kermit
  1216.     sub ax,psp        ; minus beginning...
  1217.     add bx,ax        ; # of paragraphs occupied
  1218.     mov ah,setblk
  1219.     int dos
  1220.     jc run7            ; nope...
  1221.     mov ax,ds
  1222.     mov es,ax        ; put es segment back
  1223.     mov ax,offset cmdnam    ; point to cmd name again
  1224.     call spath        ; look for it
  1225.     jc run8            ; not found, go complain
  1226.     mov dx,ax        ; point to command name
  1227.     mov al,0        ; load and execute...
  1228.     mov ah,exec
  1229.     mov bx,offset exearg    ; and to arguments
  1230.     mov ssave,sp        ; save stack ptr
  1231.     int dos            ; go run the program
  1232.     mov ax,seg datas
  1233.     mov ds,ax        ; reset data segment
  1234.     mov ax,seg stack
  1235.     mov ss,ax        ; and stack segment
  1236.     mov sp,ssave        ; restore stack ptr
  1237.     mov ah,setdma
  1238.     mov dx,offset buff
  1239.     pushf            ; save flags
  1240.     int dos            ; restore dma address!!
  1241.     popf            ; recover flags
  1242.     jc run8            ; error, handle.
  1243.     jmp rskp        ; ok, return
  1244. run7:    mov ah,prstr
  1245.     mov dx,offset erms36
  1246.     int dos
  1247.     jmp rskp
  1248. run8:    mov ah,prstr
  1249.     mov dx,offset erms37
  1250.     int dos
  1251.     jmp rskp
  1252. RUN    ENDP
  1253.  
  1254. ; the show command
  1255. showcmd    proc    near
  1256.     mov    ah,cmkey
  1257.     mov    dx,offset shotab
  1258.     xor    bx,bx            ; no canned help
  1259.     call    comnd
  1260.      jmp    r
  1261.     call    bx            ; call the handler
  1262.      jmp    r
  1263.     jmp    rskp            ; and return
  1264. showcmd    endp
  1265.  
  1266. intbrk:    cmp flags.debug,1    ; Debug mode?
  1267.     je intb1        ; Yes, then don't ignore the ^C.
  1268.     push ax
  1269.     push ds
  1270.     mov ax,seg datas
  1271.     mov ds,ax
  1272.     mov flags.cxzflg,'C'    ; Say we saw a ^C.
  1273.     mov pack.state,'A'    ; Set the state to abort.
  1274.     pop ds
  1275.     pop ax
  1276.     iret
  1277. intb1:    jmp in3ad        ; Original break interrupt address.
  1278.  
  1279. NOUT2     PROC    NEAR
  1280.     push ax
  1281.     push dx
  1282.     mov temp,10        ; Divide quotient by 10.
  1283.     cwd            ; Convert word to doubleword.
  1284.     div temp        ; AX <-- Quo, DX <-- Rem.
  1285.     cmp ax,0        ; Are we done?    
  1286.     jz nout0        ; Yes.
  1287.     call nout2        ; If not, then recurse.
  1288. nout0:    add dl,'0'        ; Make it printable.
  1289.     mov temp,ax
  1290.     mov al,dl
  1291.     stosb
  1292.     mov ax,temp
  1293.     pop dx
  1294.     pop ax
  1295.     ret            ; We're done. [21c]
  1296. NOUT2    ENDP
  1297.  
  1298. NOUT2X     PROC    NEAR
  1299.     push ax
  1300.     push dx
  1301.     push cx
  1302.     mov temp,10        ; Divide quotient by 10.
  1303.     div temp        ; AX <-- Quo, DX <-- Rem.
  1304.     mov cx,dx        ; Remember the remainder.
  1305.     cmp ax,0        ; Are we done?    
  1306.     jz nout0x        ; Yes.
  1307.     mov dx,0
  1308.     call nout2        ; If not, then recurse.
  1309. nout0x:    add cl,'0'        ; Make it printable.
  1310.     mov temp,ax
  1311.     mov al,cl
  1312.     stosb
  1313.     mov ax,temp
  1314.     pop cx
  1315.     pop dx
  1316.     pop ax
  1317.     ret            ; We're done. [21c]
  1318. NOUT2X    ENDP
  1319.  
  1320. SPATH    proc    near
  1321. ; enter with ax/ ptr to file name.  Searches path for given file,
  1322. ; returns with ax/ ptr to whole name, or carry on if file isn't
  1323. ; to be found.
  1324.     push    es
  1325.     mov    bx,ds
  1326.     mov    es,bx            ; address data segment
  1327.     mov    bx,ax            ; convenient place to keep this
  1328.     call    isfile            ; does it exist as it is?
  1329.     mov    ax,bx            ; ifso, just return original name
  1330.     jc    spath0            ; nope...
  1331.     pop    es
  1332.     ret
  1333. spath0:    mov    si,ax
  1334.     mov    di,offset tfile        ; place to copy to
  1335.     mov    dl,0            ; no '\' seen yet
  1336. spath1:    lodsb
  1337.     stosb
  1338.     cmp    al,'/'            ; contain path characters?
  1339.     je    spath1a
  1340.     cmp    al,'\'
  1341.     jne    spath2            ; no, keep going
  1342. spath1a:mov    dl,1            ; remember we've seen them
  1343. spath2:    or    al,al
  1344.     jnz    spath1            ; copy name in
  1345.     or    dl,dl            ; look at flag
  1346.     jnz    spath3            ; path embedded, file not there, fail
  1347. ; no path, keep going
  1348. spath3:    mov    si,offset pthbuf    ; path definition
  1349.     cmp    byte ptr [si],0        ; empty path?
  1350.     jne    spath4            ; no, keep going
  1351.     mov    ah,gcd            ; get current dir
  1352.     mov    dl,0            ; for default drive
  1353.     mov    si,offset defpth+1    ; place to put it
  1354.     int    dos
  1355.     mov    si,offset defpth    ; point to the path
  1356. spath4:    cmp    byte ptr [si],0        ; null, exit loop
  1357.     je    spath9
  1358.     mov    di,offset tfile        ; place to put name
  1359. spath5:    lodsb                ; get a byte
  1360.     cmp    al,';'            ; end of this part?
  1361.     je    spath7            ; yes, break loop
  1362.     cmp    al,0            ; maybe end of string?
  1363.     jne    spath6            ; no, keep going
  1364.     dec    si            ; back up over it
  1365.     jmp    short spath7        ; and break loop
  1366. spath6:    stosb                ; else stick in dest string
  1367.     jmp    spath5            ; and continue
  1368. spath7:    push    si            ; save this ptr
  1369.     mov    si,bx            ; this is user's file name
  1370.     cmp    byte ptr [di-1],'/'    ; does it end with switch char?
  1371.     je    spath8            ; yes, don't put one in
  1372.     mov    al,'\'            ; how about this one?
  1373.     cmp    byte ptr [di-1],al
  1374.     je    spath8            ; yes, don't put it in.
  1375.     stosb                ; else add one
  1376. spath8:    lodsb
  1377.     stosb
  1378.     or    al,al
  1379.     jnz    spath8            ; copy rest of name
  1380.     pop    si            ; restore pos in path def
  1381.     mov    ax,offset tfile
  1382.     call    isfile            ; is it a file?
  1383.     jc    spath4            ; no, keep looking
  1384.     mov    ax,offset tfile
  1385.     pop    es
  1386.     ret                ; return success (carry off)
  1387. spath9:    pop    es            ; restore this
  1388.     stc                ; no file found
  1389.     ret
  1390. spath    endp
  1391.  
  1392.  
  1393. isfile    proc    near
  1394. ; returns carry off if the file pointed to by ax exists
  1395.     mov    dx,ax            ; copy ptr
  1396.     mov    al,0            ; don't change anything
  1397.     mov    ah,chmod
  1398.     int    dos
  1399.     ret                ; dos sets carry
  1400. isfile    endp
  1401.  
  1402. ; Jumping to this location is like retskp.  It assumes the instruction
  1403. ;   after the call is a jmp addr.
  1404.  
  1405. RSKP    PROC    NEAR
  1406.     pop bp
  1407.     add bp,3
  1408.     push bp
  1409.     ret
  1410.  
  1411. RSKP    ENDP
  1412.  
  1413. ; Jumping here is the same as a ret.
  1414.  
  1415. R    PROC    NEAR
  1416.     ret
  1417. R    ENDP
  1418.  
  1419. code     ends            ; End of code section.
  1420.     end    start
  1421.